/**
 * Created by udi on 2016/11/26.
 */
'use strict'
const MongoClient = require('mongodb').MongoClient
const dbConfig = require("../../main/app.config").mongoConfig;
const ObjectID = require('mongodb').ObjectID

var url = `mongodb://${dbConfig.user ? dbConfig.user + ":" + dbConfig.password + "@" : ""}${dbConfig.host}:${dbConfig.port}`;

//记得最后  conn.close();
let getConn = async () => {
    let client = await MongoClient.connect(url, {useNewUrlParser: true});
    let db = client.db(dbConfig.database);
    db.close = client.close;
    return db;
}

class mongo_query {
    constructor(tableName) {
        this.skip = 0;
        this.take = 1;
        this.tableName = tableName;
    }

    where(where) {
        this.where = where
        return this;
    }

    select(columns) {
        this.columns = columns;
        return this;
    }

    order(sort) {
        this.sort = sort;
        return this;
    }

    limit(skip, take) {
        this.skip = skip;
        this.take = take;
        return this;
    }

    async toEntity() {
        this.take = 1;
        return await this._find();
    }

    async toList() {
        return await this._find(true);
    }

    async _find(list) {
        let db = await  getConn(url);
        if (!db) return;

        const collection = db.collection(this.tableName);

        try {
            let options = {};
            if (this.columns) {
                options.projection = this.columns;
            }
            options.skip = this.skip || 0;
            options.limit = this.take || 99;
            if (this.sort) {
                options.sort = this.sort;
            }

            //处理ObjectID
            if (this.where) {
                Object.keys(this.where).forEach(key => {
                    if (key == "_id") {
                        let value = this.where[key];
                        if (value && value.Type == "string") {
                            this.where[key] = ObjectID.createFromHexString(value);
                        }
                    }
                })
            }

            if (list) {
                let ret = await collection.find(this.where || {}, options).toArray();
                ret.forEach(it => {
                    if (it._id) {
                        it.id = it._id.toString();
                        delete it._id;
                    }
                });
                return ret;
            }
            else {
                let ret = await collection.findOne(this.where || {}, options)
                if (ret) {
                    if (ret._id) {
                        ret.id = ret._id.toString();
                        delete ret._id;
                    }
                }
                return ret;
            }
        }
        catch (err) {
            console.error("mongo find err:" + err);
            throw err;
        }
        finally {
            db.close();
        }
    }
}

class MongoProxy {
    constructor(tableName, entity) {
        this.tableName = tableName
        this.entity = entity;
    }

    query() {
        return new mongo_query(this.tableName);
    }

    queryById(idValue) {
        return this.query().where({_id: idValue});
    }

    async update(where, setEntity) {
        let db = await  getConn();
        if (!db) return;

        let collection = db.collection(this.tableName, this.entity);

        try {
            return await collection.updateMany(where, setEntity, true, true).updatedCount;
        }
        catch (err) {
            console.error("mongo find err:" + err);
            throw err;
        }
        finally {
            db.close();
        }
    }


    async insert(entity) {
        let db = await getConn(url);
        if (!db) return;

        let collection = db.collection(this.tableName);

        let type = entity.Type;
        try {
            let ret;
            if (type == "array") {
                entity.forEach(it => it.createAt = new Date())
                ret = await collection.insertMany(entity);

                entity.forEach(it => {
                    it.id = it._id.toString();
                });
            }
            else {
                entity.createAt = new Date();
                ret = await collection.insertOne(entity);
                entity._id = entity._id.toString();
            }

            return ret.insertedCount
        }
        catch (err) {
            console.error("mongo find err:" + err);
            throw err;
        } finally {
            db.close();
        }
    }

    async delete(where) {
        let db = await  getConn(url);
        if (!db) return;

        const collection = db.collection(this.tableName);
        try {
            return await collection.deleteMany(where).deletedCount
        }
        catch (err) {
            console.error("mongo find err:" + err);
            throw err;
        } finally {
            db.close();
        }
    }
}

exports.MongoProxy = MongoProxy

